#include "Ubicador.h"
#include "lista.h"
#include "vector_dinamico.h"

#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>

/* *****************************************************************
 *                DEFINICION DE LOS TIPOS DE DATOS
 * *****************************************************************/

/* Estructura diseñada para almacenar el archivo (identificado con un número)
 * y todas las posiciones donde se encontraría cierta palabra
 * o frase parseada. Las posiciones son identificadas con el número de
 * palabra correspondiente dentro del archivo. */
struct _Ubicador{
    lista_t* posicionesEnElArchivo;
    int numeroDelArchivo;     
    int ultimaPosicion;
};

/* ******************************************************************
 *             		IMPLEMENTACION DE PRIMITIVAS					*
 * *****************************************************************/

/* Crea y devuelve un Ubicador. 'posicion' y 'numeroArchivo' deben ser
 * positivos. En caso de error, devuelve NULL */
Ubicador_t* Ubicador_crear (int posicion, int numeroArchivo) {
	if ( (posicion < 0) || (numeroArchivo < 0) ) return NULL;
	
	Ubicador_t* ubicacion = malloc(sizeof(Ubicador_t));
	if (ubicacion == NULL) return NULL;
	
	ubicacion->posicionesEnElArchivo = lista_crear();
	if ( !(ubicacion->posicionesEnElArchivo) ) {
		free (ubicacion);
		return NULL;
	}
	
	ubicacion->ultimaPosicion = 0;
	
	if ( !(Ubicador_agregarPosicion (ubicacion, posicion)) ) {
		Ubicador_destruir (ubicacion);
		return NULL;
	}
	
	ubicacion->numeroDelArchivo = numeroArchivo;
	return ubicacion;
}

/* Agrega el número de la palabra o frase parseada al ubicador y devuelve
 * true. El resultado es false en caso de error */
bool Ubicador_agregarPosicion (Ubicador_t* ubicador, int numeroPalabra) {
	if (!ubicador) return false;
	if ( !(ubicador->posicionesEnElArchivo) ) return false;
	
	int* numero = malloc (sizeof(int));
	if (!numero) return false;
	
	*numero = numeroPalabra - ubicador->ultimaPosicion;
	ubicador->ultimaPosicion = numeroPalabra;
	return ( lista_insertar_ultimo (ubicador->posicionesEnElArchivo, numero) );
}

/* Borra el número de la palabra o frase parseada del ubicador */
void Ubicador_borrarPosicion (Ubicador_t* ubicador, int numeroPalabra) {
	lista_iter_t* iter = lista_iter_crear (ubicador->posicionesEnElArchivo);
	if (!iter) return;
	
	int* numero;
	while ( !(lista_iter_al_final (iter)) ) {
		numero = lista_iter_ver_actual (iter);
		if (*numero == numeroPalabra) break;
		lista_iter_avanzar (iter);
	}
	numero = lista_borrar (ubicador->posicionesEnElArchivo, iter);
	if (!numero) return;
	lista_iter_destruir (iter);
	free (numero);
}

/* Devuelve la lista de posiciones de la palabra o frase parseada o NULL
 * en caso de error.
 * IMPORTANTE: La lista NO debe ser destruida. */
lista_t* Ubicador_verPosiciones (Ubicador_t* ubicador) {
	if (!ubicador) return NULL;
	return ( ubicador->posicionesEnElArchivo );
}

void Ubicador_imprimir (Ubicador_t* ubicador) {
	printf ("(arch: %d, ", ubicador->numeroDelArchivo);
	
	lista_iter_t* iter = lista_iter_crear(ubicador->posicionesEnElArchivo);
	if (!iter) return;
	
	while (!lista_iter_al_final(iter)) {
		int* num = lista_iter_ver_actual (iter);
		printf ("%d, ", *num);
		lista_iter_avanzar (iter);
	}
	lista_iter_destruir (iter);
	printf (")\n");
}

/* Devuelve el número del archivo donde se encuentra la palabra o
 * frase parseada o -1 en caso de error */
int Ubicador_verArchivo (Ubicador_t* ubicador) {
	if (!ubicador) return -1;
	return ( ubicador->numeroDelArchivo );
}

/* Devuelve un vector dinámico con int* correspondientes a las posiciones
 * en los que aparece el término representado en DISTANCIAS */
vector_dinamico_t* Ubicador_verPosicionesEnVector (Ubicador_t* ub) {
	if (!ub) return NULL;
	lista_iter_t* iter = lista_iter_crear (ub->posicionesEnElArchivo);
	if (!iter) return NULL;
	
	vector_dinamico_t* vector = vector_crear ( lista_largo(ub->posicionesEnElArchivo) , NULL );
	if (!vector) {
		lista_iter_destruir(iter);
		return NULL;
	}
	
	int* pos;
	int cant = 0;
	while ( !(lista_iter_al_final (iter)) ) {
		pos = lista_iter_ver_actual (iter);
		vector_guardar (vector, cant, pos);
		lista_iter_avanzar (iter);
		cant++;
	}
	lista_iter_destruir(iter);
	return vector;
}

/* Destruye el ubicador pasado por parámetro */
void Ubicador_destruir (Ubicador_t* ubicador) {
	if (!ubicador) return;
	if ( (ubicador->posicionesEnElArchivo) != NULL) {
		lista_destruir ( ubicador->posicionesEnElArchivo, free );
	}
	free (ubicador);
}
